﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Common.Unit
{

    public static class ObjectExtensions
    {
        /// <summary>
        /// 实现深度Copy
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopy<T>(this object obj)
        {
            if (obj == null)
                return default(T);

            object result = null;

            using (var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj);
                ms.Position = 0;

                result = (T)formatter.Deserialize(ms);
                ms.Close();
            }

            return (T)result;
        }

        /// <summary>
        /// 序列化成xml使用UTF16编码方式(数据库xml字段类型必须使用UTF16)
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToUnicodeXmlBySerialiaze(this object obj)
        {
            if (obj == null)
                return null;

            Type type = obj.GetType();
            MemoryStream ms = new MemoryStream();
            string returnStr = "";
            using (XmlTextWriter xmlWriter = new XmlTextWriter(ms, Encoding.Unicode))
            {
                XmlSerializer xs = new XmlSerializer(type);
                xs.Serialize(xmlWriter, obj);
                ms.Position = 0;
                StreamReader sr = new StreamReader(ms, Encoding.Unicode);
                returnStr = sr.ReadToEnd();
                ms.Close();
            }
            return returnStr;
        }

        /// <summary>
        /// object 转换成 string[],为空则返回null
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string[] ToStringArray(this object obj)
        {
            if (obj == null || obj.ToString().Trim().Length == 0)
            {
                return null;
            }

            if (obj.GetType() == typeof(object[]))
            {
                object[] strObjArray = obj as object[];
                int objLength = strObjArray.Length;
                string[] strArray = new string[objLength];
                for (int i = 0; i < objLength; i++)
                {
                    if (strObjArray[i] == null || strObjArray[i].ToString().Length == 0)
                    {
                        continue;
                    }
                    strArray[i] = strObjArray[i].ToString();
                }
                return strArray;
            }
            else
                return new string[1] { obj.ToString() };
        }

        /// <summary>
        /// 序列化成xml使用UTF8编码方式
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToUTF8XmlBySerialiaze(this object obj)
        {
            if (obj == null)
                return null;

            Type type = obj.GetType();
            MemoryStream ms = new MemoryStream();
            string returnStr = "";
            using (XmlTextWriter xmlWriter = new XmlTextWriter(ms, Encoding.UTF8))
            {
                XmlSerializer xs = new XmlSerializer(type);
                XmlSerializerNamespaces serializerNamespace = new XmlSerializerNamespaces();
                serializerNamespace.Add("", "");
                xs.Serialize(xmlWriter, obj, serializerNamespace);
                ms.Position = 0;
                StreamReader sr = new StreamReader(ms, Encoding.UTF8);
                returnStr = sr.ReadToEnd();
                ms.Close();
            }
            return returnStr;
        }

        /// <summary>
        /// 转换成UTF8编码实现反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static T ToObjectByDeserialiaze<T>(this string xmlString)
        {
            if (xmlString == null)
                return default(T);

            Type type = typeof(T);

            T obj = default(T);
            try
            {
                using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
                {
                    using (StreamReader reader = new StreamReader(ms))
                    {
                        try
                        {
                            //reader.Normalization = false;
                            XmlSerializer xs = new XmlSerializer(type);
                            obj = (T)xs.Deserialize(reader);
                            reader.Close();
                        }
                        catch { }
                    }
                }
            }
            catch { }

            return obj;
        }

        public static string ToNullSafeString(this object obj)
        {
            if (obj == null)
                return string.Empty;
            return obj.ToString();
        }

        public static bool ToBool(this object obj)
        {
            try
            {
                return Convert.ToBoolean(obj);
            }
            catch
            {
                return false;
            }
        }

        public static decimal? ToDecimalOrNull(this object obj)
        {
            if (obj == null)
                return null;
            try
            {
                return Convert.ToDecimal(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 0;
            }
        }

        public static decimal ToDecimalOrZero(this object obj)
        {
            try
            {
                return Convert.ToDecimal(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 0;
            }
        }

        public static decimal ToDecimalOrOne(this object obj)
        {
            try
            {
                if (obj == null)
                {
                    return 1;
                }
                return Convert.ToDecimal(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 1;
            }
        }

        public static DateTime ToDateTimeOrNow(this object obj)
        {
            try
            {
                if (obj != null && obj.ToString() != "")
                {
                    return Convert.ToDateTime(obj);
                }
                else
                {
                    return DateTime.Now;
                }
            }
            catch
            {
                return DateTime.Now;
            }
        }


        public static DateTime ToDateTimeOrMin(this object obj)
        {
            try
            {
                return Convert.ToDateTime(obj);
            }
            catch
            {
                return DateTime.MinValue;
            }
        }

        public static DateTime? ToDateTimeOrNull(this object obj)
        {
            if (obj == null)
                return null;
            try
            {
                return Convert.ToDateTime(obj);
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 对于2010-12-28 的日期,返回2010-12-28 23:59:59
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static DateTime? ToBigDateTimeOrNull(this object obj)
        {
            DateTime? value = ToDateTimeOrNull(obj);
            if (value.HasValue)
            {
                return Convert.ToDateTime(value.Value.ToString("yyyy-MM-dd 23:59:59"));
            }
            return value;
        }

        public static int? ToIntOrNull(this object obj)
        {
            if (obj == null)
                return null;
            try
            {
                return Convert.ToInt32(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return null;
            }
        }

        public static int ToIntOrMinus(this object obj)
        {
            try
            {
                return Convert.ToInt32(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return -1;
            }
        }
        public static int ToIntOrZero(this object obj)
        {
            try
            {
                return Convert.ToInt32(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 0;
            }
        }

        public static short ToShortOrZero(this object obj)
        {
            try
            {
                return Convert.ToInt16(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 0;
            }
        }
        public static long ToLongOrZero(this object obj)
        {
            try
            {
                return Convert.ToInt64(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 0;
            }
        }

        public static double? ToDoubleOrNull(this object obj)
        {
            if (obj == null)
                return null;
            try
            {
                return Convert.ToDouble(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 0;
            }
        }

        public static double ToDoubleOrZero(this object obj)
        {
            try
            {
                return Convert.ToDouble(obj);
            }
            catch (OverflowException)
            {
                throw;
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// 判断string类型的object，是否为空string
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool isNullStringObject(this object obj)
        {
            if (obj == null)
                return true;
            string objStr = obj.ToString();
            if (string.IsNullOrEmpty(objStr))
                return true;
            if (objStr.Trim().Length == 0)
                return true;
            return false;

        }

        public static byte[] ToBytes(this object obj)
        {
            byte[] result = null;
            if (obj != null)
            {
                if (obj is Stream)
                {
                    Stream fs = (Stream)obj;
                    byte[] myDoc = new Byte[fs.Length];
                    fs.Read(myDoc, 0, myDoc.Length);
                    result = myDoc;
                }
                else
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    MemoryStream rems = new MemoryStream();
                    formatter.Serialize(rems, obj);
                    result = rems.GetBuffer();
                }
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static Guid ToGuidOrEmpty(this object obj)
        {
            if (obj == null)
                return Guid.Empty;
            Guid value;
            if (!Guid.TryParse(obj.ToString(), out value))
                return Guid.Empty;
            return value;
        }

        public static Guid? ToGuidOrNull(this object obj)
        {
            if (obj == null)
                return null;
            Guid value;
            if (!Guid.TryParse(obj.ToString(), out value))
                return null;
            return value;
        }

        /// <summary>
        /// 替换字符扩展
        /// </summary>
        /// <param name="obj">要替换的字符串</param>
        /// <param name="source">源字符</param>
        /// <param name="target">目标字符</param>
        /// <returns></returns>
        public static string ReplaceExt(this object obj, string[] source, string target)
        {
            if (Equals(obj, null))
                return string.Empty;
            string str = obj.ToString();
            if (source == null || source.Length == 0 || string.IsNullOrEmpty(target))
                return str;
            foreach (string s in source)
            {
                str = str.Replace(s, target);
            }
            return str;
        }

        /// <summary>
        /// 转换成百分数
        /// </summary>
        /// <param name="obj">数字</param>
        /// <param name="digit">保留位数</param>
        /// <returns></returns>
        public static string ToPercent(this object obj, int digit)
        {
            double num = 0d;
            if (obj != null)
            {
                double.TryParse(obj.ToString(), out num);
            }
            NumberFormatInfo format = new CultureInfo("zh-CN", false).NumberFormat;
            format.PercentDecimalDigits = digit;

            ////num = num * 100;
            //num = Math.Round(num * 100, digit);
            return num.ToString("p", format);
        }

        ///// <summary> 清除文本中Html的标签
        ///// </summary>
        ///// <param name="Content"></param>
        ///// <returns></returns>
        //public static string ToClearHtml(this object Content)
        //{
        //    string strContent = (Content == null) ? "" : Content.ToString();
        //    strContent = Zxj_ReplaceHtml("&#[^>]*;", "", strContent);
            
        //    string clearHtml = strContent;
        //    return clearHtml;
        //}

        /// <summary> 清除HTML标签
        /// </summary>
        /// <param name="html">必需。要去除HTML标签的文本</param>
        /// <param name="length">可选。返回去除HTML标签后返回的文本长度。</param>
        /// <returns></returns>
        public static string ToClearHTML(this object html, int length = 0)
        {
            string strHTML = (html == null) ? "" : html.ToString();
            string strText = System.Text.RegularExpressions.Regex.Replace(strHTML, "<[^>]+>", "");
            strText = System.Text.RegularExpressions.Regex.Replace(strText, "&[^;]+;", "");

            if (length > 0 && strText.Length > length)
            {
                return strText.Substring(0, length);
            }

            return strText;
        }
    }
}
